{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Router\n",
    "![Router](images/router.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import requests\n",
    "import os\n",
    "from dotenv import load_dotenv\n",
    "\n",
    "load_dotenv()\n",
    "api_key = os.getenv(\"WEATHER_API_KEY\")\n",
    "\n",
    "def get_detailed_weather_weatherapi(city: str) -> str:\n",
    "    \"\"\"\n",
    "    Fetches an extended weather report, including air quality, for a given city using WeatherAPI.\n",
    "\n",
    "    Parameters:\n",
    "        city (str): The name of the city to get the weather for.\n",
    "        api_key (str): Your WeatherAPI key.\n",
    "\n",
    "    Returns:\n",
    "        str: A detailed weather and air quality report as a text message.\n",
    "    \"\"\"\n",
    "    base_url = \"http://api.weatherapi.com/v1/current.json\"\n",
    "    params = {\n",
    "        \"key\": api_key,\n",
    "        \"q\": city,\n",
    "        \"aqi\": \"yes\"  # Include air quality data\n",
    "    }\n",
    "    \n",
    "    try:\n",
    "        response = requests.get(base_url, params=params)\n",
    "        data = response.json()\n",
    "        \n",
    "        if response.status_code == 200:\n",
    "            # Extract key weather details\n",
    "            location = data[\"location\"][\"name\"]\n",
    "            country = data[\"location\"][\"country\"]\n",
    "            temperature = data[\"current\"][\"temp_c\"]\n",
    "            feels_like = data[\"current\"][\"feelslike_c\"]\n",
    "            condition = data[\"current\"][\"condition\"][\"text\"]\n",
    "            wind_speed = data[\"current\"][\"wind_kph\"]\n",
    "            wind_direction = data[\"current\"][\"wind_dir\"]\n",
    "            humidity = data[\"current\"][\"humidity\"]\n",
    "            cloudiness = data[\"current\"][\"cloud\"]\n",
    "            last_updated = data[\"current\"][\"last_updated\"]\n",
    "\n",
    "            # Extract air quality data\n",
    "            aqi_data = data[\"current\"][\"air_quality\"]\n",
    "            co = aqi_data.get(\"co\", \"N/A\")  # Carbon Monoxide\n",
    "            no2 = aqi_data.get(\"no2\", \"N/A\")  # Nitrogen Dioxide\n",
    "            o3 = aqi_data.get(\"o3\", \"N/A\")  # Ozone\n",
    "            pm10 = aqi_data.get(\"pm10\", \"N/A\")  # Particulate Matter 10\n",
    "            pm2_5 = aqi_data.get(\"pm2_5\", \"N/A\")  # Particulate Matter 2.5\n",
    "            so2 = aqi_data.get(\"so2\", \"N/A\")  # Sulfur Dioxide\n",
    "\n",
    "            # Build the detailed weather and air quality report\n",
    "            weather_report = (\n",
    "                f\"Weather in {location}, {country}:\\n\"\n",
    "                f\"- Condition: {condition}\\n\"\n",
    "                f\"- Temperature: {temperature}°C (Feels like: {feels_like}°C)\\n\"\n",
    "                f\"- Wind: {wind_speed} kph, Direction: {wind_direction}\\n\"\n",
    "                f\"- Humidity: {humidity}%\\n\"\n",
    "                f\"- Cloudiness: {cloudiness}%\\n\"\n",
    "                f\"- Last updated: {last_updated}\\n\\n\"\n",
    "                f\"Air Quality Index (AQI):\\n\"\n",
    "                f\"- CO (Carbon Monoxide): {co} µg/m³\\n\"\n",
    "                f\"- NO2 (Nitrogen Dioxide): {no2} µg/m³\\n\"\n",
    "                f\"- O3 (Ozone): {o3} µg/m³\\n\"\n",
    "                f\"- PM10 (Particulate Matter <10µm): {pm10} µg/m³\\n\"\n",
    "                f\"- PM2.5 (Particulate Matter <2.5µm): {pm2_5} µg/m³\\n\"\n",
    "                f\"- SO2 (Sulfur Dioxide): {so2} µg/m³\"\n",
    "            )\n",
    "            return weather_report\n",
    "        else:\n",
    "            return f\"Error: {data.get('error', {}).get('message', 'Unable to fetch weather data')}\"\n",
    "    except Exception as e:\n",
    "        return f\"An error occurred: {str(e)}\"\n",
    "\n",
    "city_name = \"Berlin\"\n",
    "print(get_detailed_weather_weatherapi(city_name))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_openai import ChatOpenAI\n",
    "from langchain_core.messages import HumanMessage\n",
    "import json\n",
    "\n",
    "# OPENAI_API_KEY environment variable must be set\n",
    "llm = ChatOpenAI(model=\"gpt-4o-mini\")\n",
    "llm_tools = llm.bind_tools([get_detailed_weather_weatherapi])\n",
    "\n",
    "tool_call = llm_tools.invoke([HumanMessage(content=f\"How is the weather in Berlin?\")])\n",
    "\n",
    "print(json.dumps(vars(tool_call), indent=4))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from IPython.display import Image, display\n",
    "from langgraph.graph import StateGraph, START, END\n",
    "from langgraph.graph import MessagesState\n",
    "from langgraph.prebuilt import ToolNode\n",
    "from langgraph.prebuilt import tools_condition\n",
    "\n",
    "# Node\n",
    "def llm_with_tools(state: MessagesState):\n",
    "    return {\"messages\": [llm_tools.invoke(state[\"messages\"])]}\n",
    "\n",
    "# Build graph\n",
    "builder = StateGraph(MessagesState)\n",
    "\n",
    "builder.add_node(\"llm_with_tools\", llm_with_tools)\n",
    "builder.add_node(\"tools\", ToolNode([get_detailed_weather_weatherapi]))\n",
    "\n",
    "builder.add_edge(START, \"llm_with_tools\")\n",
    "builder.add_conditional_edges(\n",
    "    \"llm_with_tools\",\n",
    "    # If the latest message (result) from assistant is a tool call -> tools_condition routes to tools\n",
    "    # If the latest message (result) from assistant is a not a tool call -> tools_condition routes to END\n",
    "    tools_condition,\n",
    ")\n",
    "builder.add_edge(\"tools\", END)\n",
    "graph = builder.compile()\n",
    "\n",
    "# View\n",
    "display(Image(graph.get_graph().draw_mermaid_png()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_core.messages import HumanMessage\n",
    "messages = [HumanMessage(content=\"How is the weather in Berlin?\")]\n",
    "messages = graph.invoke({\"messages\": messages})\n",
    "for m in messages['messages']:\n",
    "    m.pretty_print()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from IPython.display import Image, display\n",
    "from langgraph.graph import StateGraph, START, END\n",
    "from langgraph.graph import MessagesState\n",
    "from langgraph.prebuilt import ToolNode\n",
    "from langgraph.prebuilt import tools_condition\n",
    "\n",
    "# Nodes\n",
    "def llm_with_tools(state: MessagesState):\n",
    "    return {\"messages\": [llm_tools.invoke(state[\"messages\"])]}\n",
    "\n",
    "def generate_weather_report(state: MessagesState):\n",
    "    # Extract the weather table from the last message\n",
    "    weather_table = state[\"messages\"][-1].content\n",
    "\n",
    "    prompt = f\"\"\"\n",
    "    You are a friendly and chatty weather reporter who shares the weather as if you’re experiencing it yourself in the location. \n",
    "    Your goal is to describe the weather in a way that feels personal, engaging, and easy to understand. \n",
    "    Use the provided data to create a conversational response that includes feelings and suggests possible activities based on the weather.\n",
    "\n",
    "    Here is the weather data:\n",
    "    {weather_table}\n",
    "    \n",
    "    Use the data above to create a response. Here's the tone you're aiming for:\n",
    "    1. Friendly and casual, like you're talking to a friend.\n",
    "    2. Include your personal perspective, as if you’re sitting in this weather right now.\n",
    "    3. Suggest one or two activities based on the weather.\n",
    "    4. Make your answer short: just one or two sentences.\n",
    "    \"\"\"\n",
    "\n",
    "    state[\"messages\"].append(HumanMessage(content=prompt))\n",
    "    return {\"messages\": [llm_tools.invoke(state[\"messages\"])]}\n",
    "\n",
    "# Build graph\n",
    "builder = StateGraph(MessagesState)\n",
    "builder.add_node(\"llm_with_tools\", llm_with_tools)\n",
    "builder.add_node(\"tools\", ToolNode([get_detailed_weather_weatherapi]))\n",
    "builder.add_node(\"generate_weather_report\", generate_weather_report)\n",
    "\n",
    "builder.add_edge(START, \"llm_with_tools\")\n",
    "builder.add_conditional_edges(\n",
    "    \"llm_with_tools\",\n",
    "    # If the latest message (result) from assistant is a tool call -> tools_condition routes to tools\n",
    "    # If the latest message (result) from assistant is a not a tool call -> tools_condition routes to END\n",
    "    tools_condition,\n",
    ")\n",
    "builder.add_edge(\"tools\", \"generate_weather_report\")\n",
    "builder.add_edge(\"generate_weather_report\", END)\n",
    "\n",
    "graph = builder.compile()\n",
    "\n",
    "# View\n",
    "display(Image(graph.get_graph().draw_mermaid_png()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_core.messages import HumanMessage\n",
    "messages = [HumanMessage(content=\"How are you today?\")]\n",
    "messages = graph.invoke({\"messages\": messages})\n",
    "for m in messages['messages']:\n",
    "    m.pretty_print()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_core.messages import HumanMessage\n",
    "messages = [HumanMessage(content=\"How is the weather in Berlin today?\")]\n",
    "messages = graph.invoke({\"messages\": messages})\n",
    "for m in messages['messages']:\n",
    "    m.pretty_print()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
